package com.luo.d3s.anti.mvc.ec.service.impl;

import com.luo.d3s.anti.mvc.ec.dao.CategoryMapper;
import com.luo.d3s.anti.mvc.ec.dao.GoodsMapper;
import com.luo.d3s.anti.mvc.ec.dao.GoodsTagBindingMapper;
import com.luo.d3s.anti.mvc.ec.dao.GoodsTagMapper;
import com.luo.d3s.anti.mvc.ec.model.dto.GoodsCreateDto;
import com.luo.d3s.anti.mvc.ec.model.dto.GoodsModifyDto;
import com.luo.d3s.anti.mvc.ec.model.dto.GoodsPageQueryDto;
import com.luo.d3s.anti.mvc.ec.entity.Goods;
import com.luo.d3s.anti.mvc.ec.entity.GoodsTagBinding;
import com.luo.d3s.anti.mvc.ec.enums.GoodsStatus;
import com.luo.d3s.anti.mvc.ec.service.GoodsService;
import com.luo.d3s.anti.mvc.ec.model.vo.GoodsVo;
import com.luo.d3s.core.application.assmebler.BaseAssembler;
import com.luo.d3s.core.application.dto.PageResponse;
import com.luo.d3s.core.application.dto.Response;
import com.luo.d3s.core.application.dto.SingleResponse;
import com.luo.d3s.core.util.validation.Validates;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * 商品服务实现类
 *
 * @author luohq
 * @date 2023-01-04 17:06
 */
@Service
public class GoodsServiceImpl implements GoodsService {

    @Resource
    private GoodsMapper goodsMapper;

    @Resource
    private CategoryMapper categoryMapper;

    @Resource
    private GoodsTagMapper goodsTagMapper;

    @Resource
    private GoodsTagBindingMapper goodsTagBindingMapper;

    @Override
    public SingleResponse<GoodsVo> findGoods(Long goodsId) {
        GoodsVo goodsVo = this.goodsMapper.findGoodsWithCNameById(goodsId);
        return SingleResponse.of(goodsVo);
    }

    @Override
    public PageResponse<GoodsVo> findGoodsPage(GoodsPageQueryDto goodsPageQueryDto) {
        return this.goodsMapper.findGoodsWithCNamePage(goodsPageQueryDto);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public SingleResponse<GoodsVo> createGoods(GoodsCreateDto goodsCreateDto) {
        //验证新增商品分类、标签是否存在
        this.validateGoods(goodsCreateDto.getCategoryId(), goodsCreateDto.getTagIds());
        //创建商品实体
        Goods goods = BaseAssembler.convert(goodsCreateDto, Goods.class);
        //设置商品状态
        goods.setGoodsStatus(GoodsStatus.UNSHELVED.getValue());
        //保存商品
        this.goodsMapper.insert(goods);
        //批量绑定商品标签
        this.saveGoodsTags(goods.getId(), goodsCreateDto.getTagIds());
        //转换GoodsDto
        return SingleResponse.of(BaseAssembler.convert(goods, GoodsVo.class));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Response modifyGoods(GoodsModifyDto goodsModifyDto) {
        //验证新增商品分类、标签是否存在
        this.validateGoods(goodsModifyDto.getCategoryId(), goodsModifyDto.getTagIds());
        //验证待修改商品是否存在
        Goods goods = BaseAssembler.convert(goodsModifyDto, Goods.class);
        //修改商品
        this.goodsMapper.updateById(goods);
        //批量修改商品标签
        this.saveGoodsTags(goods.getId(), goodsModifyDto.getTagIds());
        return Response.buildSuccess();
    }

    /**
     * 批量绑定商品标签列表
     *
     * @param goodsId     商品ID
     * @param goodsTagIds 标签ID集合
     */
    void saveGoodsTags(Long goodsId, Collection<Long> goodsTagIds) {
        //删除原绑定关系
        this.goodsTagBindingMapper.deleteByGoodsIds(Collections.singletonList(goodsId));
        //批量保存新的绑定关系
        if (!CollectionUtils.isEmpty(goodsTagIds)) {
            for (Long tagId : goodsTagIds) {
                GoodsTagBinding goodsTagBinding = new GoodsTagBinding(goodsId, tagId);
                this.goodsTagBindingMapper.insert(goodsTagBinding);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Response removeGoods(List<Long> goodsIds) {
        //验证是不存在已上架状态的商品才可批量删除
        Boolean existGoodsShelved = this.goodsMapper.existGoodsShelved(goodsIds);
        Validates.isFalse(existGoodsShelved, "exist shelved goods");
        //批量删除商品
        this.goodsMapper.deleteBatchIds(goodsIds);
        //批量移除商品绑定标签
        this.goodsTagBindingMapper.deleteByGoodsIds(goodsIds);
        return Response.buildSuccess();
    }

    /**
     * 上架商品 - 事务脚本实现方式
     *
     * @param goodsIds 商品ID列表
     * @return 响应结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Response shelveGoods(List<Long> goodsIds) {
        //批量更新商品状态为已上架
        this.goodsMapper.batchModifyGoodsStatus(goodsIds, GoodsStatus.SHELVED);
        return Response.buildSuccess();
    }

    /**
     * 下架商品 - 事务脚本实现方式
     *
     * @param goodsIds 商品ID列表
     * @return 响应结果
     */
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public Response unshelveGoods(List<Long> goodsIds) {
        //批量更新商品状态为已下架
        this.goodsMapper.batchModifyGoodsStatus(goodsIds, GoodsStatus.UNSHELVED);
        return Response.buildSuccess();
    }

    /**
     * 验证商品分类、标签是否存在
     *
     * @param categoryId  分类ID
     * @param goodsTagIds 标签ID集合
     */
    private void validateGoods(Long categoryId, Collection<Long> goodsTagIds) {
        //验证分类ID是否存在
        Boolean existCategory = this.categoryMapper.existCategoryId(categoryId);
        Validates.isTrue(existCategory, "category id does not exist");

        //若标签ID集合为空，则直接验证通过
        if (Objects.isNull(goodsTagIds) || goodsTagIds.isEmpty()) {
            return;
        }
        //查询存在的标签数量
        Integer existGoodsTagCount = this.goodsTagMapper.countByIdIn(goodsTagIds);
        Validates.isTrue(existGoodsTagCount.equals(goodsTagIds.size()), "goods tags don't exist");
    }
}
